package br.cin.stadium.middleware;

import java.util.ArrayList;

import br.cin.stadium.middleware.directory.StadiumDirectory;
import br.cin.stadium.middleware.event.Event;
import br.cin.stadium.middleware.event.EventRemoteListener;
import br.cin.stadium.middleware.media.Media;
import br.cin.stadium.middleware.media.MediaManager;
import br.cin.stadium.middleware.media.MediaReference;
import br.cin.stadium.middleware.util.Logger;

/**
 * Tuple space based.
 * 
 * @see StadiumTupleSpace
 * 
 * @author Fabiano, Jorge, Rafael e Vando
 */
public class StadiumTS implements StadiumTupleSpace {

	
	/**
	 * Tells if the device is or not registered into the StadiumDirectory.
	 */
	private static boolean registered = false;

	/**
	 * Represents the unique instance for Stadium Tuple Space
	 */
	private static StadiumTS instance;
	
	
	/**
	 * Private Empty Constructor 
	 */
	private StadiumTS() {
		Logger.log("StadiumTS", "Construtor", "BEGIN");
		try {
			registerUnit();
		} catch (StadiumException e) {
			Logger.log("Error in register Unit - do not stop - try to Register before each operation");
		}
		Logger.log("StadiumTS", "Construtor", "END");
	}

	/**
	 * Returns the StadiumTupleSpace interface - Use to access all StadiumSpace methods. 
	 */
	public static StadiumTupleSpace getInstance() {
		Logger.log("StadiumTS", "getInstance", "Begin");
		if(instance == null) {
			instance = new StadiumTS();
		}
		
		Logger.log("StadiumTS", "getInstance", "End");
		return instance;
	}
	

	/* (non-Javadoc)
	 * @see br.cin.stadium.middleware.StadiumTupleSpace#write(br.cin.stadium.middleware.media.Media)
	 */
	public boolean write(Media media) throws StadiumException {
		Logger.log("StadiumTS", "write", "Begin (" + media.getName() + ")");

		if (!registered) {
			registerUnit();
		}
		
		boolean success = MediaManager.getInstance().write(media); 

		Logger.log("StadiumTS", "write", "END (" + success + ")");
		return success;
	}

	/* (non-Javadoc)
	 * @see br.cin.stadium.middleware.StadiumTupleSpace#read(java.lang.String)
	 */
	public ArrayList<MediaReference> read(String mediaName) throws StadiumException {
		Logger.log("StadiumTS", "read (byName)", "Begin (" + mediaName + ")");

		if (!registered) {
			registerUnit();
		}
		
		ArrayList<MediaReference> retorno = MediaManager.getInstance().read(mediaName, Event.OPCODE_READ_FROM_NAME);

		Logger.log("StadiumTS", "read (byName)", "End (" + retorno.size() + ")");
		return retorno;
	}

	/* (non-Javadoc)
	 * @see br.cin.stadium.middleware.StadiumTupleSpace#readAll()
	 */
	public ArrayList<MediaReference> readAll() throws StadiumException {
		Logger.log("StadiumTS", "readAll", "Begin");

		if (!registered) {
			registerUnit();
		}

		ArrayList<MediaReference> retorno = MediaManager.getInstance().read(null, Event.OPCODE_READ_ALL_MEDIA);

		Logger.log("StadiumTS", "readAll", "End (" + retorno.size() + ")");
		return retorno;
	}

	/* (non-Javadoc)
	 * @see br.cin.stadium.middleware.StadiumTupleSpace#read(int)
	 */
	public ArrayList<MediaReference> read(int stadiumSection)  throws StadiumException {
		Logger.log("StadiumTS", "read (bySector)", "Begin (" + stadiumSection + ")");

		if (!registered) {
			registerUnit();
		}

		ArrayList<MediaReference> retorno = MediaManager.getInstance().read(stadiumSection, Event.OPCODE_READ_FROM_SECTOR);

		Logger.log("StadiumTS", "read (bySector)", "End (" + retorno.size() + ")");
		return retorno;
	}

	/* (non-Javadoc)
	 * @see br.cin.stadium.middleware.StadiumTupleSpace#requestMedia(br.cin.stadium.middleware.media.MediaReference)
	 */
	public Media requestMedia(MediaReference mediaReference) throws StadiumException {
		Logger.log("StadiumTS", "requestMedia", "Begin (" + mediaReference.getMediaName() + "," + 
				                                            mediaReference.getSector() + "," +
				                                            mediaReference.getServerLocation().getIp() + "," +
				                                            mediaReference.getServerLocation().getPort() + ")");

		if (!registered) {
			registerUnit();
		}
		
		Media m = MediaManager.getInstance().requestMedia(mediaReference);

		Logger.log("StadiumTS", "requestMedia", "End (" + m.getType() + "," + m.getContent().length + ")");
		return m;
	}

	/* (non-Javadoc)
	 * @see br.cin.stadium.middleware.StadiumTupleSpace#take()
	 */
	public void take() {

	}

	/* (non-Javadoc)
	 * @see br.cin.stadium.middleware.StadiumTupleSpace#notifyAllDevices()
	 */
	public void notifyMediaChanges(EventRemoteListener listener, int sector) {
		MediaManager.getInstance().addEventRemoteListener(listener, sector);
	}

	
	/**
	 * Register the Unit/Device into the StadiumDirectory
	 * @throws StadiumException 
	 */
	private void registerUnit() throws StadiumException {
		Logger.log("StadiumTS", "registerUnit", "Begin");

		try {
			StadiumDirectory.getInstance().bind();
		} catch (StadiumException e) {
			throw new StadiumException("Error in Register Process");
		}
		registered = true;


		Logger.log("StadiumTS", "registerUnit", "End");
	}

	/* (non-Javadoc)
	 * @see br.cin.stadium.middleware.StadiumTupleSpace#unRegisterUnit()
	 */
	public void unRegisterUnit() throws StadiumException {
		Logger.log("StadiumTS", "unRegisterUnit", "Begin");

		StadiumDirectory.getInstance().unBind();
		registered = false;
		
		Logger.log("StadiumTS", "unRegisterUnit", "End");
	}




}